package client.profesor;

import static client.common.libs.Underscore._;
import static org.stjs.javascript.JSCollections.$array;

import org.stjs.javascript.Array;
import org.stjs.javascript.Map;

import client.common.EndPoints.ProfesorEP;
import client.common.Models.CalificacionPeriodo;
import client.common.Models.Curso;
import client.common.Models.Estudiante;
import client.common.Models.Indicador;
import client.common.Models.IndicadorEstudiantePeriodo;
import client.common.angular.EmptyPromise;
import client.common.angular.NgScope;
import client.common.directives.EPLoading;
import client.common.javascript.JsConsole;
import client.common.javascript.JsFunction1;
import client.common.javascript.JsProcedure1;

public class AsignaturaActualScope extends NgScope {
	public Curso curso;
	public Array<Indicador> indicadores;
	public Map<String, Array<IndicadorEstudiantePeriodo>> indicadoresEstudiantes;
	private EPLoading epLoading;
	private ProfesorEP profesorEP;
	private Map<String, Long> stateParams;
	private Long idMateria;
	protected Array<Estudiante> estudiantes;

	public static Array<String> $inject() {
		return $array("Profesor", "$stateParams", "epLoading");
	}

	public AsignaturaActualScope(final ProfesorEP profesorEP,
			final Map<String, Long> stateParams, EPLoading epLoading) {
		super("AsignaturaScope");
		this.epLoading = epLoading;
		this.profesorEP = profesorEP;
		this.stateParams = stateParams;
		this.idMateria = stateParams.$get("idMateria");
		final AsignaturaActualScope self = this;

		curso = profesorEP.getCurso((Long) stateParams.$get("idCurso"),
				new JsProcedure1<Curso>() {
					@Override
					public void $invoke(Curso p) {

						self.indicadores = profesorEP.getIndicadores(
								self.idMateria, self.curso.idGrado);

						self.estudiantes = profesorEP.getEstudiantesCurso(p.id);
					}

				});

		profesorEP.getIndicadoresEstudiantes(stateParams.$get("idCurso"),
				stateParams.$get("idMateria"),
				new JsProcedure1<Array<IndicadorEstudiantePeriodo>>() {

					@Override
					public void $invoke(
							Array<IndicadorEstudiantePeriodo> indicadoresPeriodo) {

						self.indicadoresEstudiantes = _.groupBy(
								indicadoresPeriodo, "idEstudiante");

					}
				});

	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void addIndicador(final Estudiante e, final Indicador indic) {

		if (indicadoresEstudiantes.$get(e.id + "") == null) {
			indicadoresEstudiantes.$put(e.id + "", (Array) $array());
		}
		final AsignaturaActualScope self = this;
		IndicadorEstudiantePeriodo i = new IndicadorEstudiantePeriodo() {
			{
				idEstudiante = e.id;
				idMateria = self.stateParams.$get("idMateria");
				idGrado = self.curso.idGrado;
				categoriaIndicador = indic.categoria;
				consecutivoIndicador = indic.consecutivo;
				idPeriodo = indic.idPeriodo;

			}
		};

		epLoading.$invoke(profesorEP.newIndicadorEstudiante(i,
				new JsProcedure1<IndicadorEstudiantePeriodo>() {
					@Override
					public void $invoke(IndicadorEstudiantePeriodo p) {
						self.indicadoresEstudiantes.$get(e.id + "").push(p);
					}

				}), "#ep-cal-cort-" + e.id);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void removeIndicador(final Estudiante e,
			final IndicadorEstudiantePeriodo indicaOut) {

		if (indicadoresEstudiantes.$get(e.id + "") == null) {
			indicadoresEstudiantes.$put(e.id + "", (Array) $array());
		}
		final AsignaturaActualScope self = this;

		epLoading.$invoke(profesorEP.deleteIndicadorEstudiante(e.id,
				stateParams.$get("idMateria"), curso.idGrado,
				indicaOut.categoriaIndicador.toString(),
				indicaOut.consecutivoIndicador,
				new JsProcedure1<EmptyPromise>() {

					@Override
					public void $invoke(EmptyPromise p) {
						_.remove(
								self.indicadoresEstudiantes.$get(e.id + ""),
								new JsFunction1<Boolean, IndicadorEstudiantePeriodo>() {

									@Override
									public Boolean $invoke(
											IndicadorEstudiantePeriodo indicIn) {

										return indicIn.categoriaIndicador
												.toString() == indicaOut.categoriaIndicador
												.toString()
												&& indicIn.consecutivoIndicador == indicaOut.consecutivoIndicador;
									}

								});
					}
				}), "#ep-cal-cort-" + e.id);
	}

	public void changeCalificacion(final Estudiante e, final String grade) {

		final AsignaturaActualScope self = this;

		epLoading.$invoke(
				profesorEP.setCalificacionPeriodo(new CalificacionPeriodo() {
					{
						idEstudiante = e.id;
						idMateria = self.stateParams.$get("idMateria");
						idGrado = self.curso.idGrado;
						nota = grade;
					}
				}), "#ep-cal-cort-" + e.id);
	}

	public void algo(int toindex, int fromindex, final String categoriaIndic) {
		final AsignaturaActualScope self = this;
		int step = (fromindex < toindex) ? -1 : 1;

		Array<Integer> indicadoresSource = _.map(
				_.filter(
						indicadoresEstudiantes.$get(""
								+ estudiantes.$get(fromindex).id),
						new JsFunction1<Boolean, IndicadorEstudiantePeriodo>() {

							@Override
							public Boolean $invoke(IndicadorEstudiantePeriodo t1) {
								JsConsole.console.log(t1.categoriaIndicador);
								JsConsole.console.log(categoriaIndic);
								return t1.categoriaIndicador == categoriaIndic;
							}
						}),
				new JsFunction1<Integer, IndicadorEstudiantePeriodo>() {

					@Override
					public Integer $invoke(IndicadorEstudiantePeriodo t1) {
						// TODO Auto-generated method stub
						return t1.consecutivoIndicador;
					}

				});
		JsConsole.console.log(indicadoresSource);
		final Array<Estudiante> ii = $array(new Estudiante());
		for (int i = toindex; i != fromindex; i += step) {
			Array<Integer> indicadoresTarget = _.map(_.filter(
					indicadoresEstudiantes.$get("" + estudiantes.$get(i).id),
					new JsFunction1<Boolean, IndicadorEstudiantePeriodo>() {

						@Override
						public Boolean $invoke(IndicadorEstudiantePeriodo t1) {
							JsConsole.console.log(t1.categoriaIndicador);
							JsConsole.console.log(categoriaIndic);
							return t1.categoriaIndicador == categoriaIndic;
						}
					}), new JsFunction1<Integer, IndicadorEstudiantePeriodo>() {

				@Override
				public Integer $invoke(IndicadorEstudiantePeriodo t1) {

					return t1.consecutivoIndicador;
				}

			});

			Array<Integer> toAdd = _.difference(indicadoresSource,
					indicadoresTarget);

			ii.$set(0, estudiantes.$get(i));
			_.forEach(toAdd, new JsProcedure1<Integer>() {
				@Override
				public void $invoke(final Integer consec) {
					self.addIndicador(ii.$get(0), new Indicador() {
						{
							categoria = categoriaIndic;
							consecutivo = consec;
							idMateria = self.idMateria;
							idGrado = self.curso.idGrado;
						}
					});
				}
			});
			Array<Integer> toRemove = _.difference(indicadoresTarget,
					indicadoresSource);
			_.forEach(toRemove, new JsProcedure1<Integer>() {

				@Override
				public void $invoke(final Integer consec) {
					self.removeIndicador(ii.$get(0),
							new IndicadorEstudiantePeriodo() {
								{
									categoriaIndicador = categoriaIndic;
									consecutivoIndicador = consec;
									idMateria = self.idMateria;
									idGrado = self.curso.idGrado;
									idEstudiante = ii.$get(0).id;
								}
							});
				}
			});

		}
	}

	public void sendMessage() {
		// Profesor.sendMessage({}, {
		// idEstudiante : $scope.toEstudiante.id,
		// mensaje : $scope.msg
		// }, function() {
		//
		// epModal.close("mensaje-estudiante");
		// $scope.toEstudiante = undefined;
		// $scope.msg = undefined;
		// });

	}
}
